package com.bsdk.install.device.impl;

import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.bsdk.common.core.domain.AjaxResult;
import com.bsdk.common.utils.DateUtils;
import com.bsdk.common.utils.SpringContextUtil;
import com.bsdk.install.device.IDeviceLockLoraService;
import com.bsdk.install.device.lockLora.LockLora;
import com.bsdk.install.device.lockLora.LockLoraFactory;
import com.bsdk.install.domain.*;
import com.bsdk.install.queue.PublicQueue;
import com.bsdk.install.rabbitmq.RabbitMqKeys;
import com.bsdk.install.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class DeviceLockLoraService implements IDeviceLockLoraService {

    @Autowired
    private IGatewayService gatewayService;
    @Autowired
    private IDeviceService deviceService;
    @Autowired
    private IDeviceBatchService deviceBatchService;
    @Autowired
    private IDeviceBatchInfoService deviceBatchInfoService;
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private IDeviceOpenLogService deviceOpenLogService;

    @Override
    public AjaxResult open(Long id) {

        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandOpenRemote();

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                        //逻辑处理
                        //存入开锁记录

                        if(jsData.getInteger("code") == 200){
                            Device device = deviceService.getById(id);
                            DeviceOpenLog deviceOpenLog = new DeviceOpenLog();
                            deviceOpenLog.setOpenTime(DateUtils.getNowDate());
                            deviceOpenLog.setDeviceId(id);
                            deviceOpenLog.setSn(device.getSn());
                            deviceOpenLog.setNumber(0);
                            deviceOpenLog.setType(0);
                            deviceOpenLog.setValue(null);
                            deviceOpenLogService.save(deviceOpenLog);
                            //放入rabbitmq
                            JSONObject resultAnalysis= new JSONObject(){{
                                put("openTime",deviceOpenLog.getOpenTime());
                                put("deviceId",deviceOpenLog.getDeviceId());
                                put("sn",deviceOpenLog.getSn());
                                put("number",deviceOpenLog.getNumber());
                                put("type",deviceOpenLog.getType());
                                put("value",deviceOpenLog.getValue());
                            }};
                            //推送到平台
//                            rabbitTemplate.convertAndSend(RabbitMqKeys.MQ_EXCHANGE_TOPIC,
//                                    RabbitMqKeys.PUSH_FLATS_DATA_LOCK_TOPIC,
//                                    resultAnalysis,
//                                    new CorrelationData(UUID.randomUUID().toString()));

                        }
                        log.info("逻辑处理中");
                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }

    }
    @Override
    public AjaxResult close(Long id) {

        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandCloseRemote();

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                        //逻辑处理
                        log.info("逻辑处理中");
                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }

    }
    //

    @Override
    public AjaxResult syncTime(Long id) {
        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandSyncTime();

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                        //逻辑处理
                        log.info("逻辑处理中");
                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult syncTime(String sn,Boolean result ) {
        AjaxResult resultLockLora = this.getLockLora(sn);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandSyncTime();

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"),result);

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        if(result){

                            JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                            //逻辑处理
                            log.info("逻辑处理中");
                            return AjaxResult.success(jsData);
                        }else {
                            return AjaxResult.success();
                        }

                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult batchSyncTime(String[] sns,Long batchId) {

        //查询批量器
        DeviceBatch batch = deviceBatchService.getById(batchId);
        if(batch == null){
            return AjaxResult.error("不存在批量数据");

        }else{
            //构建分组器
            //遍例设备
            List<Device> listDevice = deviceService.list(new LambdaQueryWrapper<Device>().in(Device::getSn,sns));
            log.info(JSONObject.toJSONString(listDevice));
            for (Device device:listDevice){
                //查询是否存在通卡信息
                DeviceBatchInfo _info = deviceBatchInfoService.getOne(new LambdaQueryWrapper<DeviceBatchInfo>().eq(DeviceBatchInfo::getBatchId,batch.getId()).eq(DeviceBatchInfo::getBatchType,batch.getBatchType()).eq(DeviceBatchInfo::getDeviceId,device.getId()).last(" limit 1"));
                if(_info == null){
                    DeviceBatchInfo info = new DeviceBatchInfo();

                    info.setBatchId(batch.getId());
                    info.setDeviceId(device.getId());
                    info.setStatus(1);
                    info.setSubset(device.getGatewayId());
                    info.setBatchType(batch.getBatchType());
                    info.setCreateTime(batch.getCreateTime());
                    info.setStatus(0);
                    //插入推送列表
                    deviceBatchInfoService.saveOrUpdate(info);

                }

            }
            this.distribute(batch);

        }

        return AjaxResult.success();
    }

    /**
     * 批量器 分组数据
     * @param batch
     * @return
     */
    public void distribute(DeviceBatch batch) {

        Map<Long,List<DeviceBatchInfo>> mainMap= new HashMap<>();
        //失败与0的数据重新分组
        List<DeviceBatchInfo> batchList = deviceBatchInfoService.list(new LambdaQueryWrapper<DeviceBatchInfo>().eq(DeviceBatchInfo::getBatchId,batch.getId()).and(wp->wp.eq(DeviceBatchInfo::getStatus,0).or().eq(DeviceBatchInfo::getStatus,4)));
        for (DeviceBatchInfo batchInfo:batchList){

            batchInfo.setStatus(1);
            batchInfo.updateById();
            if(mainMap.containsKey(batchInfo.getSubset())){

                List<DeviceBatchInfo> list = mainMap.get(batchInfo.getSubset());
                list.add(batchInfo);
                mainMap.put(batchInfo.getSubset(),list);
            }else{
                List<DeviceBatchInfo> list= new ArrayList<>();
                list.add(batchInfo);
                mainMap.put(batchInfo.getSubset(),list);

            }
        }
        buildBatchThread(batch,mainMap);


    }

    /**
     * 建立线程队列
     * @param batch
     * @param mainMap
     */
    public void buildBatchThread(DeviceBatch batch,Map<Long,List<DeviceBatchInfo>> mainMap){
        Set<Long> keyset = mainMap.keySet();

        for(Long key:keyset){

            Thread thread = new Thread(() -> {

                for(DeviceBatchInfo batchInfo:mainMap.get(key)){
                    log.info("key:"+key);
                    //查询设备
                    AjaxResult ajaxResult;
                    try {
                        if(batchInfo.getBatchType().equals("syncTime")){
                            ajaxResult = syncTime(batchInfo.getDeviceId());

                        } else if (batchInfo.getBatchType().equals("addUser")) {
                            ajaxResult = addOrEditUser(batchInfo.getDeviceId(),false,batch.getType(),batch.getValue(),batch.getStartDate(),batch.getEndDate(),null,0,batch.getNumber());
                        }else{
                            ajaxResult = open(batchInfo.getDeviceId());
                        }
                        //重组rabbitmq数据
                        JSONObject jsonObject1 = new JSONObject();
                        jsonObject1.put("id",batchInfo.getId());

                        jsonObject1.put("deviceId",batchInfo.getDeviceId());
                        jsonObject1.put("batchType",batchInfo.getBatchType());
                        jsonObject1.put("data", ajaxResult.get("data"));

                        log.info("结果是："+JSONObject.toJSONString(jsonObject1));
                        rabbitTemplate.convertAndSend(RabbitMqKeys.MQ_EXCHANGE_TOPIC,
                                RabbitMqKeys.CLIENT_PUSH_DATA_LOCK_TOPIC,
                                JSONObject.toJSONString(jsonObject1),
                                new CorrelationData(UUID.randomUUID().toString()));


                        if(ajaxResult.isSuccess()){

                            JSONObject jsonObject = (JSONObject) ajaxResult.get("data");
                            if(jsonObject!= null){

                                if( jsonObject.getInteger("code") == 200){

                                    //更新状态
                                    batchInfo.setStatus(3);
                                    batchInfo.updateById();
                                }else{
                                    //更新状态
                                    batchInfo.setStatus(4);
                                    batchInfo.setError(jsonObject.getString("code"));
                                    batchInfo.updateById();

                                }

                            }else{
                                batchInfo.setError("网关未应答");
                                batchInfo.setStatus(4);
                                batchInfo.updateById();

                            }
                        }
                    }catch (Exception e){
                        log.error(e.getMessage());
                        log.info("出错了");
                    }


                }

            });
            thread.start();

        }


    }
    @Override
    public AjaxResult addOrEditUser(Long id, boolean admin,String pwType, String pw, Date startTime, Date endTime, JSONObject cycle,int times,int userId) {
        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandAddUser(admin,pwType, pw, startTime, endTime, userId,cycle,times);

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));
                log.info("MQTT发送结果："+JSONObject.toJSONString(resultSend));
                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));

                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }
    @Override
    public AjaxResult addOrEditUser(Long id, boolean admin,String pwType, String pw, Date startTime, Date endTime, int userId) {
        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandAddUser(admin, pwType,pw, startTime, endTime, userId);

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult activeOrDisableUser(Long id, boolean active, int userId) {

        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandActiveOrDisableUser(active, userId);

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));

                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult editPasswordById(Long id, String pw, int userId) {
        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandEditPasswordById(pw, userId);

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                        //逻辑处理
                        log.info("逻辑处理中");
                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult addKey(Long id, String key) {
        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandAddKey(key);

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                        //逻辑处理
                        log.info("逻辑处理中");
                        Device device = new Device();
                        device.setId(id);
                        device.setPwKey(key);
                        deviceService.updateById(device);
                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult editExpireTimeById(Long id, Date startTime, Date endTime, int userId) {

        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandEditExpireTimeById(startTime, endTime, userId);

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                        //逻辑处理
                        log.info("逻辑处理中");
                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult deleteUserById(Long id, int userId) {
        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandDeleteUserById(userId);

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));

                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult getBriefPassword(Long id, Date startTime, Integer duration) {
        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            Device device = deviceService.getById(id);

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandGetBriefPassword(startTime, duration, device.getPwKey());

            if (resultCommand.isSuccess()) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("password", resultCommand.get("msg"));
                //返回密码
                return AjaxResult.success(jsonObject);


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    @Override
    public AjaxResult reset(Long id) {
        AjaxResult resultLockLora = this.getLockLora(id);

        if (resultLockLora.isSuccess()) {

            LockLora lockLora = (LockLora) resultLockLora.get("data");

            AjaxResult resultCommand = lockLora.commandReset();

            if (resultCommand.isSuccess()) {

                //发送命令
                AjaxResult resultSend = this.send((JSONObject) resultCommand.get("data"));

                if (resultSend == null) {

                    return AjaxResult.error("设备通讯失败");

                } else {
                    if (resultSend.isSuccess()) {
                        JSONObject jsData = lockLora.result((JSONObject) resultSend.get("data"));
                        //逻辑处理
                        log.info("逻辑处理中");
                        return AjaxResult.success(jsData);
                    } else {
                        return resultSend;
                    }
                }


            } else {
                return resultCommand;
            }

        } else {

            return resultLockLora;
        }
    }

    public AjaxResult getLockLora(Long id) {

        Device device = deviceService.getById(id);

        if (device.getGatewayId() == 0) {

            return AjaxResult.error("门锁未配置网关");

        } else {

            Gateway gateway = gatewayService.getById(device.getGatewayId());


            //根据版本 获取对应指令
            LockLora lockLora;
            if (device.getVersion() != null) {
                switch (device.getVersion()) {
                    case "1.0.0":
                    default:
                        lockLora = new LockLoraFactory().createLockV("v1", gateway.getDevId(), device.getMac());
                        break;

                }

                if (lockLora != null) {
                    return AjaxResult.success(lockLora);
                } else {
                    return AjaxResult.error("Lora锁创建异常");
                }

            } else {
                return AjaxResult.error("门锁版本未设置");
            }


        }

    }
    public AjaxResult getLockLora(String sn) {

        Device device = deviceService.getOne(new LambdaQueryWrapper<Device>().eq(Device::getSn, sn).last("limit 1"));

        if (device.getGatewayId() == 0) {

            return AjaxResult.error("门锁未配置网关");

        } else {

            Gateway gateway = gatewayService.getById(device.getGatewayId());


            //根据版本 获取对应指令
            LockLora lockLora;
            if (device.getVersion() != null) {
                switch (device.getVersion()) {
                    case "1.0.0":
                    default:
                        lockLora = new LockLoraFactory().createLockV("v1", gateway.getDevId(), device.getMac());
                        break;

                }

                if (lockLora != null) {
                    return AjaxResult.success(lockLora);
                } else {
                    return AjaxResult.error("Lora锁创建异常");
                }

            } else {
                return AjaxResult.error("门锁版本未设置");
            }


        }

    }
    public AjaxResult getLockLora(Long id,String devId) {

        Device device = deviceService.getById(id);

        //根据版本 获取对应指令
        LockLora lockLora;

        if (device.getVersion() != null) {
            switch (device.getVersion()) {
                case "1.0.0":
                default:
                    lockLora = new LockLoraFactory().createLockV("v1", devId, device.getMac());
                    break;

            }

            if (lockLora != null) {
                return AjaxResult.success(lockLora);
            } else {
                return AjaxResult.error("Lora锁创建异常");
            }

        } else {
            return AjaxResult.error("门锁版本未设置");
        }




    }
    public AjaxResult getLockLora(Device device) {

        if (device.getGatewayId() == 0) {

            return AjaxResult.error("门锁未配置网关");

        } else {

            Gateway gateway = gatewayService.getById(device.getGatewayId());


            //根据版本 获取对应指令
            LockLora lockLora;

            if (device.getVersion() != null) {

                switch (device.getVersion()) {
                    case "1.0.0":
                    default:
                        lockLora = new LockLoraFactory().createLockV("v1", gateway.getDevId(), device.getMac());
                        break;

                }

                if (lockLora != null) {
                    return AjaxResult.success(lockLora);
                } else {
                    return AjaxResult.error("Lora锁创建异常");
                }

            } else {
                return AjaxResult.error("门锁版本未设置");
            }


        }
    }

    private AjaxResult send(JSONObject jsonObject) {

        SpringContextUtil.getBean(PublicQueue.class).setDown(jsonObject);

        if (PublicQueue.MAPRESULTQUEUE.containsKey(jsonObject.getString("uId"))) {
            JSONObject jsonObject1 = null;
            try {
                jsonObject1 = (JSONObject) PublicQueue.MAPRESULTQUEUE.get(jsonObject.getString("uId")).poll(10, TimeUnit.SECONDS);


            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return AjaxResult.success(jsonObject1);

        } else {
            return AjaxResult.error("结果队列不存在");
        }

    }

    /**
     * 不需要结果
     * @param jsonObject
     * @param result
     * @return
     */
    private AjaxResult send(JSONObject jsonObject,Boolean result) {

        SpringContextUtil.getBean(PublicQueue.class).setDown(jsonObject);
        if (result){

            if (PublicQueue.MAPRESULTQUEUE.containsKey(jsonObject.getString("uId"))) {
                JSONObject jsonObject1 = null;
                try {
                    jsonObject1 = (JSONObject) PublicQueue.MAPRESULTQUEUE.get(jsonObject.getString("uId")).poll(10, TimeUnit.SECONDS);


                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                return AjaxResult.success(jsonObject1);

            } else {
                return AjaxResult.error("结果队列不存在");
            }

        }else {
            return AjaxResult.success();
        }


    }
}
